package cn.bellychang.ood.litejunit.v3.framework.runners;

import cn.bellychang.ood.litejunit.v3.framework.annotation.After;
import cn.bellychang.ood.litejunit.v3.framework.annotation.Before;
import cn.bellychang.ood.litejunit.v3.framework.notification.Failure;
import cn.bellychang.ood.litejunit.v3.framework.notification.RunNotifier;
import cn.bellychang.ood.litejunit.v3.framework.runner.Description;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author ChangLiang
 * @date 2020/5/28
 */
public class TestMethodRunner extends BeforeAndAfterRunner {

    private final Object test;

    private final Method method;

    private final RunNotifier notifier;

    private final TestIntrospector testIntrospector;

    private final Description description;

    public TestMethodRunner(Object test, Method method, RunNotifier notifier, Description description) {
        super(test.getClass(), Before.class, After.class, test);
        this.test = test;
        this.method = method;
        this.notifier = notifier;
        this.description = description;
        testIntrospector = new TestIntrospector(test.getClass());
    }

    public void run() {
        notifier.fireTestStarted(description);
        try {
            runMethod();
        } finally {
            notifier.fireTestFinished(description);
        }
    }

    private void runMethod() {
        runProtected();
    }

    @Override
    protected void runUnprotected() {
        try {
            executeMethodBody();
        } catch (InvocationTargetException e) {
            addFailure(e);
        } catch (Throwable e) {
            addFailure(e);
        }
    }

    private void executeMethodBody() throws InvocationTargetException, IllegalAccessException {
        method.invoke(test);
    }

    @Override
    protected void addFailure(Throwable targetException) {
        notifier.fireTestFailure(new Failure(description,targetException));
    }


}
